package com.dy.yunying.biz.service.manage.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dy.yunying.api.dto.SonGameDto;
import com.dy.yunying.api.entity.ParentGameDO;
import com.dy.yunying.api.entity.ParentGameVersionDO;
import com.dy.yunying.api.entity.WanGameDO;
import com.dy.yunying.api.entity.WanGameImgsDO;
import com.dy.yunying.api.enums.PackTypeEnum;
import com.dy.yunying.api.req.WanGameImgsReq;
import com.dy.yunying.api.req.WanGameReq;
import com.dy.yunying.api.vo.GameVersionVO;
import com.dy.yunying.api.vo.WanGameReqVo;
import com.dy.yunying.api.vo.WanGameVersionVO;
import com.dy.yunying.biz.dao.manage.ext.*;
import com.dy.yunying.biz.service.manage.*;
import com.dy.yunying.biz.utils.DateUtils;
import com.google.api.client.util.Lists;
import com.pig4cloud.pig.common.core.util.EBeanUtil;
import lombok.SneakyThrows;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author ：lile
 * @date ：2021/5/29 16:25
 * @description：
 * @modified By：
 */
@Service
public class GameServiceImpl extends ServiceImpl<GameDOMapperExt, WanGameDO> implements GameService {

	private static final Map<String, Field> GAME_FILED_MAP = Arrays.stream(WanGameDO.class.getDeclaredFields()).collect(Collectors.toMap(Field::getName, e -> e));

	@Autowired
	private GameDOMapperExt gameDOMapperExt;
	@Autowired
	private WanGameAreaDOMapperExt wanGameAreaDOMapperExt;
	@Autowired
	private WanGameImgsDOMapperExt wanGameImgsDOMapperExt;
	@Autowired
	private ParentGameDOMapperExt parentGameDOMapperExt;
	@Autowired
	private WanCmsConfigService wanCmsConfigService;
	@Autowired
	private ParentGameService parentGameService;
	@Autowired
	private WanGameSupplierService wanGameSupplierService;
	@Autowired
	private ParentGameVersionService parentGameVersionService;
	@Autowired
	private GameVersionDOMapperExt gameVersionDOMapperExt;

	@Autowired
	private RedisTemplate<String, String> redisTemplate;

	/**
	 * 上传地址
	 */
	@Value("${game.img.download.url}")
	private String imgUrl;

	/**
	 * 上传地址
	 */
	@Value("${game.apk.icon.url}")
	private String iconUrl;


	@Override
	public int deleteByPrimaryKey(Long id) {
		return gameDOMapperExt.deleteByPrimaryKey(id);
	}

	@Override
	public int insert(WanGameDO record) {
		return gameDOMapperExt.insert(record);
	}

	@Override
	public int insertSelective(WanGameDO record) {
		return gameDOMapperExt.insertSelective(record);
	}

	@Override
	public WanGameDO selectByPrimaryKey(Long id) {
		return gameDOMapperExt.selectByPrimaryKey(id);
	}

	@Override
	public WanGameDO selectVOByPK(Long id) {
		if (id == null) {
			return null;
		}
		WanGameDO wanGameDO = null;
		String redisKey = "tmp:com:yy:game:" + id;
		String jsonStr = redisTemplate.opsForValue().get(redisKey);
		if (StringUtils.isNotBlank(jsonStr)) {
			wanGameDO = JSON.parseObject(jsonStr, WanGameDO.class);
		} else {
			wanGameDO = gameDOMapperExt.selectVOByPK(id);
			if (wanGameDO != null) {
				redisTemplate.opsForValue().set(redisKey, JSON.toJSONString(wanGameDO), 2, TimeUnit.HOURS);
			}
		}
		return wanGameDO;
	}

	@Override
	public List<WanGameDO> selectVOByPKs(List<Long> gameIdList) {
		return gameDOMapperExt.selectVOByPKs(gameIdList);
	}

	@Override
	public WanGameVersionVO selectVersionVOByPK(Long id, Integer packType) {
		return gameDOMapperExt.selectVersionVOByPK(id, packType);
	}

	@Override
	public List<WanGameVersionVO> versionVOList(WanGameDO req) {
		return gameDOMapperExt.versionVOList(req);
	}

	@Override
	public List<Map<String, Object>> versionVOTree(WanGameDO req) {
		List<Map<String, Object>> result = new ArrayList<>();
		Map<Long, List<WanGameVersionVO>> parentGameMap = new HashMap<>();
		List<WanGameVersionVO> gameList = gameDOMapperExt.versionVOList(req);
		if (CollectionUtils.isNotEmpty(gameList)) {
			for (WanGameVersionVO game : gameList) {
				Long pgid = game.getPgid();
				List<WanGameVersionVO> sonGameList = parentGameMap.get(pgid);
				if (sonGameList == null) {
					sonGameList = new ArrayList<>();
					parentGameMap.put(pgid, sonGameList);
				}
				sonGameList.add(game);
			}
			for (Map.Entry<Long, List<WanGameVersionVO>> entry : parentGameMap.entrySet()) {
				Long pgid = entry.getKey();
				List<WanGameVersionVO> sonGameList = entry.getValue();
				Map<String, Object> pgameInfo = new HashMap<>();
				pgameInfo.put("id", pgid);
				pgameInfo.put("title", sonGameList.get(0).getGname());
				pgameInfo.put("children", sonGameList);
				pgameInfo.put("spread", true);
				result.add(pgameInfo);
			}
		}
		return result;
	}

	@Override
	public int updateByPrimaryKeySelective(WanGameDO record) {
		return gameDOMapperExt.updateByPrimaryKeySelective(record);
	}

	@Override
	public int updateByPrimaryKey(WanGameDO record) {
		return gameDOMapperExt.updateByPrimaryKey(record);
	}

	/**
	 * 获取可缓存的子游戏列表
	 *
	 * @param req
	 * @return
	 * @throws Exception
	 */
	@Override
	public List<WanGameDO> getCacheableGameList(WanGameReq req) throws Exception {
		final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		final String keyPrefix = "com:yy:game:";
		Collection<Long> ids = req.getIds();
		List<WanGameDO> resultList = new ArrayList<>();

		// 首先从redis中获取子游戏
		Set<Long> notExistsIdSet = new HashSet<>();
		redisTemplate.setHashValueSerializer(new StringRedisSerializer());
		HashOperations<String, String, String> forHash = redisTemplate.opsForHash();
		for (Long id : ids) {
			Map<String, String> beanMap = forHash.entries(keyPrefix + id);
			if (!beanMap.isEmpty()) {
				resultList.add(EBeanUtil.stringMapToObject(beanMap, WanGameDO.class, GAME_FILED_MAP, (c, v) -> {
					try {
						return c == Date.class ? sdf.parse(v) : null;
					} catch (ParseException ignore) {
						return null;
					}
				}));
			} else {
				notExistsIdSet.add(id);
			}
		}
		if (notExistsIdSet.isEmpty()) {
			return resultList;
		}
		// 从数据库中查询缓存没有的数据
		LambdaQueryWrapper<WanGameDO> wrapper = Wrappers.<WanGameDO>query().lambda().in(WanGameDO::getId, notExistsIdSet).orderByDesc(WanGameDO::getId);
		List<WanGameDO> gameList = getBaseMapper().selectList(wrapper);
		resultList.addAll(gameList);
		// 将从数据库查询出的主游戏信息写入redis
		redisTemplate.execute(new SessionCallback<Object>() {
			@SneakyThrows
			@Override
			public Object execute(RedisOperations operations) throws DataAccessException {
				operations.multi();
				for (WanGameDO game : gameList) {
					String key = keyPrefix + game.getId();
					Map<String, String> beanMap = EBeanUtil.objectToStringMap(game, v -> v instanceof Date ? sdf.format(v) : null);
					operations.opsForHash().putAll(key, beanMap);
					operations.expire(key, 5 * 60, TimeUnit.SECONDS);
				}
				operations.exec();
				return null;
			}
		});

		return resultList;
	}

	/**
	 * 游戏列表
	 *
	 * @param
	 * @return
	 */
	@Override
	public IPage<WanGameReqVo> selectGameList(WanGameReq req) {
		IPage<WanGameReqVo> pageList = gameDOMapperExt.selectGameList(req);
		if (pageList.getRecords() != null || pageList.getRecords().size() > 0) {
			//子游戏充值统计
			List<WanGameReqVo> listRecharge = gameDOMapperExt.statRechargeSumByGame();
			//获取父游戏名称
			List<ParentGameDO> parentGameList = parentGameDOMapperExt.selectParentGameListByCond(new ParentGameDO());
			// 主游戏版本列表
			List<ParentGameVersionDO> parentGameVersionDOList = parentGameVersionService.getPackTypeByGameId(req.getPgid().longValue());
			// 子游戏版本列表
			List<BigInteger> gameIds = pageList.getRecords().stream().map(WanGameReqVo::getId).collect(Collectors.toList());
			List<GameVersionVO> gameVersionVOList = gameVersionDOMapperExt.getSonGamePackType(gameIds);

			WanGameImgsReq wgi = new WanGameImgsReq();
			pageList.getRecords().forEach(gr -> {
				gr.setImgpath(imgUrl);
				gr.setAppiconpath(iconUrl);
				parentGameList.forEach(pgo -> {
					if (pgo.getId() == gr.getPgid().longValue()) {
						gr.setPgname(pgo.getGname());
					}
				});
				//获取游戏详情图片（多图）
				wgi.setGid(gr.getId().intValue());
				List<WanGameImgsDO> wanGameImgs = wanGameImgsDOMapperExt.selectWanGameImgList(wgi);
				if (null != wanGameImgs) {
					StringBuffer imgName = new StringBuffer();
					wanGameImgs.forEach(giList -> {
						imgName.append(giList.getImgurl()).append(",");
					});
					gr.setDetailsimg(imgName.toString());
				}
				//统计游戏付费金额
				listRecharge.forEach(lr -> {
					if (gr.getId().compareTo(lr.getId()) == 0) {
						gr.setRecharge(lr.getRecharge());
					}
				});
				// 主游戏版本
				if (CollectionUtils.isNotEmpty(parentGameVersionDOList)){
					List<Map<String, String>> parentGameVersionList = Lists.newArrayList();
					for (ParentGameVersionDO parentGameVersion : parentGameVersionDOList){
						Map<String, String> map = new HashMap<>();
						map.put("packType", String.valueOf(parentGameVersion.getPackType()));
						map.put("packTypeText", PackTypeEnum.getName(parentGameVersion.getPackType()));
						map.put("name", parentGameVersion.getName());
						map.put("code", String.valueOf(parentGameVersion.getCode()));
						map.put("status", String.valueOf(parentGameVersion.getStatus()));
						map.put("versionId", String.valueOf(parentGameVersion.getVersionId()));
						map.put("versionTime", DateUtils.dateToString(parentGameVersion.getCreateTime(), DateUtils.YYYY_MM_DD_HH_MM_SS));
						parentGameVersionList.add(map);
					}
					gr.setParentGameVersionList(parentGameVersionList);
				}
				// 子游戏版本
				if (CollectionUtils.isNotEmpty(gameVersionVOList)){
					List<Map<String, String>> sonGameVersionList = Lists.newArrayList();
					for (GameVersionVO gameVersion : gameVersionVOList){
						if (String.valueOf(gameVersion.getGameId()).equals(String.valueOf(gr.getId()))){
							Map<String, String> map = new HashMap<>();
							map.put("packType", String.valueOf(gameVersion.getPackType()));
							map.put("packTypeText", PackTypeEnum.getName(gameVersion.getPackType()));
							map.put("name", gameVersion.getName());
							map.put("code", String.valueOf(gameVersion.getCode()));
							map.put("status", String.valueOf(gameVersion.getStatus()));
							map.put("versionId", String.valueOf(gameVersion.getVersionId()));
							map.put("versionTime", DateUtils.dateToString(gameVersion.getCreateTime(), DateUtils.YYYY_MM_DD_HH_MM_SS));
							sonGameVersionList.add(map);
						}
					}
					gr.setSonGameVersionList(sonGameVersionList);
				}
			});
		}
		return pageList;
	}

	/**
	 * 根据查询条件获取游戏信息
	 *
	 * @param map
	 * @return
	 */
	@Override
	public WanGameReqVo selectWanGameByCond(Map<String, Object> map) {
		return gameDOMapperExt.selectWanGameByCond(map);
	}

	/**
	 * 根据查询条件获取游戏list
	 *
	 * @param
	 * @return
	 */
	@Override
	public List<WanGameDO> selectWanGameListByCond(WanGameDO req) {
		return gameDOMapperExt.selectWanGameListByCond(req);
	}

	/**
	 * 新增游戏
	 *
	 * @param entity
	 * @return
	 */
	@Override
	public BigInteger insertWanGame(WanGameReqVo entity) {
		BigInteger gameId = gameDOMapperExt.insertWanGame(entity) ? entity.getId() : null;
		if (gameId != null) {
			//添加wan_game_supplier配置
			ParentGameDO pgname = parentGameService.getByPK(entity.getPgid().longValue());
			wanGameSupplierService.addGameSupplier(entity, pgname);
			//刷新缓存
			//sysConfigBean.refreshSysConfig();
			//添加配置信息
			wanCmsConfigService.insertWanCmsConfig("游戏中心-" + entity.getGname(), "1", "games", gameId.intValue());
		}
		return gameId;
	}

	/**
	 * 删除，批量删除
	 *
	 * @param
	 * @return
	 */
	@Override
	public Map<String, Object> batchDelete(String[] ids) {
		Map<String, Object> resultMap = new HashMap<String, Object>();
		String msg = "";
		int num_1 = 0;
		int num_2 = 0;
		List<Integer> idList = new ArrayList<>();
		for (int i = 0; i < ids.length; i++) {
			//查询该游戏下是否绑定区服
			Map<String, Object> searchAreaCountMap = new HashMap<String, Object>();
			searchAreaCountMap.put("gid", new BigInteger(ids[i]));
			int count = wanGameAreaDOMapperExt.selectAreaCountByMap(searchAreaCountMap);
			if (count == 0) {
				boolean flag = gameDOMapperExt.updateGameIsDelAndStatusById(new BigInteger(ids[i]));
				if (flag) {
					idList.add(Integer.parseInt(ids[i]));
					num_1++;
				}
			} else {
				msg = msg + "游戏id为：" + ids[i] + "绑定区服数有：" + count + ",";
				num_2++;
			}
		}
		if (ids.length == (num_1 + num_2)) {
			resultMap.put("code", "操作成功");
			msg = StringUtils.isNotBlank(msg) ? msg : "删除成功！";
			resultMap.put("msg", msg);
			resultMap.put("ids", idList);
		} else {
			resultMap.put("code", "操作成功");
			resultMap.put("msg", "删除失败！");
		}
		return resultMap;
	}

	/**
	 * 修改游戏
	 *
	 * @author cx
	 * @date 2020年7月24日11:07:02
	 */
	@Override
	public boolean updateWanGameByPrimaryKey(WanGameReqVo entity) {
		return gameDOMapperExt.updateWanGameByPrimaryKey(entity) == 1 ? true : false;
	}

	@Override
	public List<SonGameDto> selectDtoByPKs(List<Long> gameIdList) {
		return gameDOMapperExt.selectDtoByPKs(gameIdList);
	}

	@Override
	public List<SonGameDto> getAutoPackListByPgid(Long pgid) {
		return gameDOMapperExt.getAutoPackListByPgid(pgid);
	}

}
